#include "minecraftscenedata.h"
MineCraftSceneData::MineCraftSceneData()
{
    builder = new MineCraftSceneBuilder();
    builder->setParent(this);
    builder->scene = this;
}

QVector3D MineCraftSceneData::extend() const
{
    return m_world.extend;
}

void MineCraftSceneData::setExtends(const QVector3D &newExtends)
{
    resize(newExtends);
}

void MineCraftSceneData::requestRebuild()
{
    m_building = true;
    rebuild();
    m_building = false;
    emit buildFinished();
}

MineCraftSceneBuilder *MineCraftSceneData::getBuilder() const
{
    return builder;
}

void MineCraftSceneData::setBuilder(MineCraftSceneBuilder *newBuilder)
{
    if (builder == newBuilder)
        return;
    builder = newBuilder;
    emit builderChanged();
}

void MineCraftSceneData::resize(QVector3D newSize)
{
    if (m_world.extend == newSize)
        return;
    WorldData newWorld;
    if(!newSize.isNull())//创建新世界的缓冲区
    {
        newWorld.blocks = new BlockData[newSize.x() * newSize.y() * newSize.z()];
        newWorld.extend = newSize;
    }

    int dx = std::min(m_world.extend.x(),newWorld.extend.x());
    int dy = std::min(m_world.extend.y(),newWorld.extend.y());
    int dz = std::min(m_world.extend.z(),newWorld.extend.z());

    if(m_world.blocks)//如果旧世界有数据，那么拷贝到新世界中
    {
        for(int x = 0;x< dx;x++)
        {
            for(int y = 0;y< dy;y++)
            {
                for(int z = 0;z< dz;z++)
                {
                    *get(m_world,x,y,z) = *get(newWorld,x,y,z);
                }
            }
        }
    }

    m_world = std::move(newWorld);//新世界数据移动到旧世界上
    emit extendChanged();
    emit buildFinished();
}

MineCraftSceneBuilder::MineCraftSceneBuilder()
{
    m_defaultBrush = new MineCraftDefaultBrush();
    m_defaultBrush->setParent(this);
    m_ctxs << Context();
    reset();
}

void MineCraftSceneBuilder::push()
{
    m_ctxs << curCtx();
}

void MineCraftSceneBuilder::pop()
{
    if(m_ctxs.size() != 1)
    {
        m_ctxs.pop_back();
    }
}

void MineCraftSceneBuilder::reset()
{
    Context ctx;
    ctx.brush = m_defaultBrush;
    curCtx() = ctx;
}

MineCraftSceneBrush *MineCraftSceneBuilder::brush()
{
    return curCtx().brush;
}

void MineCraftSceneBuilder::setBrush(MineCraftSceneBrush *brush)
{
    if(brush == curCtx().brush)
    {
        return;
    }
    curCtx().brush = brush;
    emit brushChanged();
}

MineCraftSceneBuilder::BuildMode MineCraftSceneBuilder::buildMode()
{
    return curCtx().buildMode;
}

void MineCraftSceneBuilder::setBuildMode(BuildMode mode)
{
    if(mode == curCtx().buildMode)
    {
        return;
    }
    curCtx().buildMode = mode;
    emit buildModeChanged();
}

QVector3D MineCraftSceneBuilder::blockRotation()
{
    return curCtx().blockRotation;
}

void MineCraftSceneBuilder::setBlockRotation(QVector3D rotation)
{
    if(rotation == curCtx().blockRotation)
    {
        return;
    }
    curCtx().blockRotation = rotation;
    emit blockRotationChanged();
}

QVariant MineCraftSceneBuilder::customData()
{
    return curCtx().custom;
}

void MineCraftSceneBuilder::setCustomData(QVariant v)
{
    if(v == curCtx().custom)
    {
        return;
    }
    curCtx().custom = v;
    emit customDataChanged();
}

void MineCraftSceneBuilder::translate(QVector3D position)
{
    auto &ctx = curCtx();
    QMatrix4x4 mat;
    mat.translate(position);
    ctx.transform = ctx.transform * mat;
}

void MineCraftSceneBuilder::rotate(QVector3D rotation)
{
    auto &ctx = curCtx();
    QMatrix4x4 mat;
    mat.rotate(QQuaternion::fromEulerAngles(rotation));
    ctx.transform = ctx.transform * mat;
}

void MineCraftSceneBuilder::drawBlock(QVector3D point)
{
    point = mapPoint(point);
    applyBlock(point);
}

void MineCraftSceneBuilder::drawBox(QVector3D start, QVector3D extends)
{
    for(int x = 0;x<extends.x();x++)
    {
        for(int y = 0;y<extends.y();y++)
        {
            for(int z = 0;z<extends.z();z++)
            {
                QVector3D point = QVector3D(x,y,z) + start;
                point = mapPoint(point);
                applyBlock(point);
            }
        }
    }
}


void MineCraftSceneBuilder::drawBoxShell(QVector3D start, QVector3D extends)
{
    //空壳盒体的绘制可以看作对6个厚度为1的实心盒体的绘制
    //绘制底面和顶面
    drawBox(start,{extends.x(),1,extends.z()});
    if(extends.y() > 1)
    {
        drawBox(start + QVector3D{0,extends.y() - 1,0},{extends.x(),1,extends.z()});
    }

    //绘制xy平面
    if(extends.y() > 2)
    {
        drawBox(start + QVector3D{0,1,0},{extends.x(),extends.y() - 2,1});
        if(extends.z() > 1)
        {
            drawBox(start + QVector3D{0,1,extends.z() - 1},{extends.x(),extends.y() - 2,1});
        }

        if(extends.z() > 2 )
        {
            drawBox(start + QVector3D{0,1,1},{1,extends.y() - 2,extends.z() - 2});
            if(extends.x() > 1)
            {
                drawBox(start + QVector3D{extends.x() - 1,1,1},{1,extends.y() - 2,extends.z() - 2});
            }
        }
    }
}

void MineCraftSceneBuilder::drawBoxFrame(QVector3D start, QVector3D extends)
{

}

QVector3D MineCraftSceneBuilder::mapPoint(QVector3D point)
{
    return curCtx().transform.map(point);
}

void MineCraftSceneBuilder::applyBlock(QVector3D point)
{
    auto& ctx = curCtx();

    auto block = scene->get(point.x(),point.y(),point.z());

    if(!block)
    {
        return;
    }



    if(ctx.buildMode == Override ||
        (ctx.buildMode == Add && block->type == BlockMeta::None) ||
        (ctx.buildMode == Modify && block->type != BlockMeta::None))
    {
        auto brush = ctx.brush;
        auto type = brush?brush->getBlock(point):BlockMeta::None;
        if(type == BlockMeta::None)
        {
            return;
        }
        block->type = type;
        block->custom = ctx.custom;
        block->rotation = ctx.blockRotation;
    }
    else if(ctx.buildMode == Remove)
    {
        block->type = BlockMeta::None;
        block->custom = {};
        block->rotation = {};
    }
}

MineCraftSceneBuilder::Context &MineCraftSceneBuilder::curCtx()
{
    return m_ctxs.back();
}

MineCraftDefaultBrush *MineCraftSceneBuilder::defaultBrush() const
{
    return m_defaultBrush;
}

void MineCraftSceneBuilder::setDefaultBrush(MineCraftDefaultBrush *newDefaultBrush)
{
    if (m_defaultBrush == newDefaultBrush)
        return;
    m_defaultBrush = newDefaultBrush;
    emit defaultBrushChanged();
}

MineCraftDefaultBrush::MineCraftDefaultBrush()
{

}

BlockMeta::BlockType MineCraftDefaultBrush::getBlock(const QVector3D &position)
{
    return m_type;
}

BlockMeta::BlockType MineCraftDefaultBrush::type() const
{
    return m_type;
}

void MineCraftDefaultBrush::setType(const BlockMeta::BlockType &newType)
{
    if (m_type == newType)
        return;
    m_type = newType;
    emit typeChanged();
}

MineCraftSceneBrush::MineCraftSceneBrush()
{

}

MineCraftRandomBrush::MineCraftRandomBrush()
{

}

BlockMeta::BlockType MineCraftRandomBrush::getBlock(const QVector3D &position)
{
    float value = gen.generateDouble();
    if(value <= m_threthold)
    {
        return m_type;
    }
    return BlockMeta::None;
}

int MineCraftRandomBrush::getSeed() const
{
    return seed;
}

void MineCraftRandomBrush::setSeed(int newSeed)
{
    if (seed == newSeed)
        return;
    gen = QRandomGenerator(seed);
    emit seedChanged();
}

BlockMeta::BlockType MineCraftRandomBrush::type() const
{
    return m_type;
}

void MineCraftRandomBrush::setType(const BlockMeta::BlockType &newType)
{
    if (m_type == newType)
        return;
    m_type = newType;
    emit typeChanged();
}

float MineCraftRandomBrush::threthold() const
{
    return m_threthold;
}

void MineCraftRandomBrush::setThrethold(float newThrethold)
{
    if (qFuzzyCompare(m_threthold, newThrethold))
        return;
    m_threthold = newThrethold;
    emit thretholdChanged();
}
